from flask import request, jsonify, make_response
import urllib.parse
from flask_restx import Namespace, Resource, fields
from app import db
from app.models.file import File
from app.models.department import Department
from werkzeug.utils import secure_filename

ns = Namespace('files', description='文件管理')

# 文件上传模型
upload_parser = ns.parser()
upload_parser.add_argument('file', location='files', type='file', required=True, help='文件')
upload_parser.add_argument('department_id', type=int, required=False, help='部门ID')
upload_parser.add_argument('folder_name', type=str, required=False, help='文件夹名称')

# 获取文件列表
get_files_parser = ns.parser()
get_files_parser.add_argument('department_id', type=int, required=False, help='部门ID')
get_files_parser.add_argument('search', type=str, required=False, help='搜索关键词')

@ns.route('/')
class FileList(Resource):
    @ns.expect(get_files_parser)
    def get(self):
        args = get_files_parser.parse_args()
        department_id = args.get('department_id')
        search = args.get('search')

        query = File.query

        if department_id:
            query = query.filter_by(department_id=department_id)

        if search:
            query = query.filter(File.name.like(f'%{search}%'))

        files = query.all()
        return {'files': [file.to_dict() for file in files]}

    def post(self):
        # 从请求中获取文件
        file = request.files.get('file')
        print(f"调试: 收到文件上传请求 - 文件名: {file.filename if file else '无文件'}")
        if not file:
            print("调试: 未接收到文件")
            return {'message': '文件是必需的'}, 400

        # 获取部门ID
        department_id = request.form.get('department_id')
        if department_id:
            try:
                department_id = int(department_id)
            except ValueError:
                return {'message': '部门ID必须是整数'}, 400

        # 检查部门是否存在
        if department_id:
            department = Department.query.get_or_404(department_id)
        else:
            department = None

        # 获取文件名和类型
        # 保留原始文件名，特别是中文文件名
        filename = file.filename
        # 确保文件名安全，移除潜在危险字符但保留中文
        filename = ''.join(c for c in filename if c.isalnum() or c in '._- ' or ord(c) > 127)
        # 去除首尾空格
        filename = filename.strip()
        # 如果文件名是空的，设置一个默认名
        if not filename:
            filename = 'unnamed_file'
        # 改进文件类型识别逻辑
        if '.' in filename:
            file_ext = filename.rsplit('.', 1)[1].lower()
            # 映射常见文件扩展名到标准MIME类型
            mime_types = {
                'pdf': 'pdf',
                'doc': 'msword',
                'docx': 'vnd.openxmlformats-officedocument.wordprocessingml.document',
                'xls': 'vnd.ms-excel',
                'xlsx': 'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'ppt': 'vnd.ms-powerpoint',
                'pptx': 'vnd.openxmlformats-officedocument.presentationml.presentation',
                'jpg': 'jpeg',
                'jpeg': 'jpeg',
                'png': 'png',
                'gif': 'gif'
            }
            file_type = mime_types.get(file_ext, file_ext)
        else:
            # 对于没有扩展名的文件，尝试根据文件名猜测类型
            # 检查文件名是否包含常见文件类型关键词
            filename_lower = filename.lower()
            # 打印调试信息
            print(f"调试: 无扩展名文件 - 文件名: {filename}, 尝试识别类型")
            
            if 'doc' in filename_lower:
                file_type = 'msword'
                print(f"调试: 识别为Word文档")
            elif any(excel in filename_lower for excel in ['xls', 'excel', 'spreadsheet']):
                file_type = 'vnd.ms-excel'
                print(f"调试: 识别为Excel文档")
            elif 'ppt' in filename_lower:
                file_type = 'vnd.ms-powerpoint'
                print(f"调试: 识别为PowerPoint文档")
            elif 'pdf' in filename_lower:
                file_type = 'pdf'
                print(f"调试: 识别为PDF文档")
            elif any(img in filename_lower for img in ['jpg', 'jpeg', 'png', 'gif', 'image']):
                file_type = 'jpeg'  # 默认使用jpeg作为图片类型
                print(f"调试: 识别为图片")
            else:
                file_type = 'unknown'
                print(f"调试: 无法识别文件类型")

        # 读取文件内容
        content = file.read()
        file_size = len(content)

        # 获取文件夹名称
        folder_name = request.form.get('folder_name')
        print(f"调试: 文件夹名称: {folder_name}")

        # 创建文件记录
        new_file = File(
            name=filename,
            content=content,
            file_type=file_type,
            file_size=file_size,
            department_id=department_id,
            folder_name=folder_name
        )

        db.session.add(new_file)
        db.session.commit()
        print(f"调试: 文件保存成功 - ID: {new_file.id}, 文件名: {new_file.name}")

        return new_file.to_dict(), 201

@ns.route('/<int:id>')
class FileDetail(Resource):
    def get(self, id):
        file = File.query.get_or_404(id)
        return file.to_dict()

    def delete(self, id):
        file = File.query.get_or_404(id)

        # 删除数据库记录
        db.session.delete(file)
        db.session.commit()

        return {'message': '文件已删除'}, 200

@ns.route('/download/<int:id>')
class FileDownload(Resource):
    def get(self, id):
        file = File.query.get_or_404(id)
        # 确保文件内容是字节类型
        content = file.content if isinstance(file.content, bytes) else bytes(file.content)
        
        # 使用生成器流式传输大文件
        def generate():
            chunk_size = 8192
            for i in range(0, len(content), chunk_size):
                yield content[i:i+chunk_size]
        
        response = make_response(generate())
        # 设置正确的Content-Type
        if file.file_type in ['pdf']:
            content_type = f'application/{file.file_type}'
        elif file.file_type in ['msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document', 'vnd.ms-excel', 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'vnd.ms-powerpoint', 'vnd.openxmlformats-officedocument.presentationml.presentation']:
            content_type = f'application/{file.file_type}'
        elif file.file_type in ['jpeg', 'png', 'gif']:
            content_type = f'image/{file.file_type}'
        else:
            content_type = 'application/octet-stream'
        response.headers.set('Content-Type', content_type)
        # 使用RFC 5987标准编码文件名
        encoded_filename = urllib.parse.quote(file.name.encode('utf-8'))
        # 只使用filename*参数避免latin-1编码问题
        response.headers.set('Content-Disposition', f'attachment; filename*=UTF-8\'\'{encoded_filename}')
        # 对于分块传输，不应该设置Content-Length头
        # 设置Transfer-Encoding为chunked以支持流式传输
        response.headers.set('Transfer-Encoding', 'chunked')
        return response